#ifndef ARRAY_H
#define ARRAY_H
#include "common.h"
#include "etypes.h"
#include "emem.h"
#define apush(a, e) a = array_push(a, e)

#define fexce ({float _e_; *((unsigned int*)&_e_) = 0xffffffff; _e_;})

#define Array_Initialize_Size 5
#define d_malloc(n, t) Malloc( (n + 1) * sizeof(t) + sizeof(unsigned int) * 2 )
#define d_free(a) Mfree( a )

#define array_max(a) ((unsigned int*)&(a)[-1])[-2]
#define array_n(a) ((unsigned int*)&(a)[-1])[-1]
#define get_exce(a) (a[-1])
#define array_new(t, n, exce) ({t* _a_ = (t*)d_malloc(n, t); \
                              ((unsigned int*)_a_)[0] = n; \
                              ((unsigned int*)_a_)[1] = 0; \
                              ((t*)&((unsigned int*)_a_)[2])[0] = exce; \
                              &((t*)&((unsigned int*)_a_)[2])[1];} )
#define array_delete(a) d_free( &((unsigned int*)&(a)[-1])[-2] )

#define array_safe_get(a, i) ( (i < array_n(a) && i >= 0) ? (a)[i] : get_exce(a) )
#define array_safe_get_ptr(a, i) ( (i < array_n(a) && i >= 0) ? &(a)[i] : NULL )
#define array_safe_set(a, i, e) ( (i < array_n(a) && i >= 0) ? (a)[i] = e : get_exce(a) )
#define array_push(a, e) ({ \
                             (a)[array_n(a)] = e; \
                             array_n(a)++; \
                             (array_n(a) < array_max(a)) ? (a) \
                             : \
                             ({ \
                                 typeof((a)) _b_; \
                                 _b_ = d_malloc( array_max(a) * 2, typeof(*(a)) ); \
                                 ((unsigned int*)_b_)[0] = array_max(a) * 2; \
                                 ((unsigned int*)_b_)[1] = array_n(a); \
                                 ((typeof((a)))&((unsigned int*)_b_)[2])[0] = (a)[-1];\
                                 _b_ = &((typeof((a)))&((unsigned int*)_b_)[2])[1]; \
                                 memcpy(_b_, (a), sizeof( typeof(*(a)) ) * array_n((a)) ); \
                                 d_free( &((unsigned int*)&(a)[-1])[-2] ); \
                                 _b_; \
                              });\
                          })

#define array_pop(a) (array_n(a) > 0) ? ({ typeof(*(a)) _e_ = (a)[array_n(a) - 1]; array_n(a)--; _e_;}) : (a)[-1]
#define array_grow(a, n) ({ \
                              typeof((a)) _b_; \
                              _b_ = d_malloc( array_max(a) + n, typeof(*(a)) ); \
                              ((unsigned int*)_b_)[0] = array_max(a) + n; \
                              ((unsigned int*)_b_)[1] = array_n(a); \
                              ((typeof((a)))&((unsigned int*)_b_)[2])[0] = (a)[-1];\
                              _b_ = &((typeof((a)))&((unsigned int*)_b_)[2])[1]; \
                              memcpy(_b_, a, sizeof( typeof(*(a)) ) * array_n((a)) ); \
                              d_free( &((unsigned int*)&(a)[-1])[-2] ); \
                              _b_; \
                          })

#define array_resize(a, n) (array_n(a) < n) ? ({uint _count_ = (n) - array_n(a); for (uint _i_ = 0; _i_ < _count_; _i_++) a = array_push(a, get_exce(a)); a;}) : ({array_n(a) = n; a;})
#endif
